<template>
    <div id="container">
        <div id="editor-box">
            <canvas id="THREE-canvas"></canvas>
        </div>
        <div class="panel">
            <h2>控制器模式切换</h2>
            <!-- <button @click="changeTransformMode('translate')">平移</button>
            <button @click="changeTransformMode('rotate')">旋转</button> -->
            <h2>设备编辑</h2>
            <button @click="handleAddDevice('side')">添加侧面设备</button>
            <button @click="handleAddDevice('inside')">添加内部设备</button>
        </div>
    </div>
</template>

<script setup>
import { onMounted, onUnmounted, ref, shallowRef, h, createApp } from 'vue';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { TransformControls } from 'three/examples/jsm/controls/TransformControls.js';
import * as TWEEN from '@tweenjs/tween.js';
import Light from '@/utils/Editor/Light';
import { loadByUrl } from '@/utils/Editor/Loader';
import { enableAxesHelper } from '@/utils/Editor/Helper';
import CSSManager from '@/utils/Editor/Manager/CSSManager';
import ShapeEditor from '@/components/ShapeEditor.vue';
import { scaleZStrategy } from '@/editor/GreenHouse/Strategies';

let scene, renderer;


/**
 * @type {OrbitControls}
 */
let orbitControls;
/**
 * @type {TransformControls}
 */
let transformControls;
/**
 * @type{THREE.PerspectiveCamera}
 */
let camera;
/**
 * @type{CSSManager}
 */
let cssManager
/**
 * @type{PlantPlot}
 */
let box;
let building;;

function animate() {
    requestAnimationFrame(animate);
    TWEEN.update();
    renderer.render(scene, camera);
    cssManager && cssManager.render()
    orbitControls.update();
}

function loadBuilding() {
    const baseScale = 0.5;
    loadByUrl('3D/building/new/dapeng001.fbx', baseScale).then((model) => {
        building = model;

        // 整体缩放模型
        const Ztest = 5
        model.scale.set(baseScale * 2, baseScale * 2, baseScale)

        /** @type {(sideMesh: THREE.Mesh) => void} */
        const sideStrategy = (sideMesh) => {
            // name为1和3
            sideMesh.scale.setY(sideMesh.scale.y * Ztest)
            sideMesh.position.z += 10 * (Ztest - 1)
            // 贴图重复
            if (sideMesh.isMesh && Array.isArray(sideMesh.material)) {
                sideMesh.material.forEach((mat) => {
                    if (mat.map) {
                        const texture = mat.map
                        texture.wrapS = THREE.RepeatWrapping;
                        texture.wrapT = THREE.RepeatWrapping;
                        texture.repeat.setX(Ztest);
                    }
                });
            }
        }

        /** @type {(mesh: THREE.Mesh) => void} */
        const backStrategy = (mesh) => {
            mesh.position.z = -400 * (Ztest - 1);
        }
        /** @type {(mesh: THREE.Mesh) => void} */
        const bottomStrategy = (mesh) => {
            // 一格的长度是 400
            mesh.scale.setY(mesh.scale.y * Ztest)
            mesh.position.z += 10 * (Ztest - 1)
        }
        const topStrategy = (mesh, model) => {
            // 复制 Ztest - 1 个模型
            for (let i = 0; i < Ztest - 1; i++) {
                // 复制一个child模型
                const newChild = mesh.clone();
                newChild.name = `5-${i + 1}`
                // Z轴偏移 -400个单位
                model.add(newChild);
                newChild.position.setZ(-400 * (i + 1))
            }
        }


        // model.traverse((child) => {
        //     if (child.isMesh) {
        //         switch (child.name) {
        //             case '1':
        //                 sideStrategy(child)
        //                 break;
        //             case '3':
        //                 sideStrategy(child)
        //                 break;
        //             // case '2':
        //             //     backStrategy(child)
        //             //     break;
        //             case '5':
        //                 topStrategy(child, model)
        //                 break;
        //             case '4':
        //                 backStrategy(child)
        //                 break;
        //             case '6':
        //                 bottomStrategy(child)
        //             default:
        //                 break;
        //         }
        //     }

        //     // if (child.isMesh && child.name === '5') {
        //     //     // 向上取整

        //     //     child.scale.setY(Math.ceil(child.scale.z) / Ztest)
        //     //     for (let i = 0; i < Ztest - 1; i++) {
        //     //         // 复制一个child模型
        //     //         const newChild = child.clone();
        //     //         const getSize = (model) => {
        //     //             const box = new THREE.Box3().setFromObject(model);
        //     //             return box.getSize(new THREE.Vector3());
        //     //         }
        //     //         const size = getSize(newChild)
        //     //         newChild.name = `5-${i + 1}`
        //     //         model.add(newChild);
        //     //         newChild.position.set(0, 0, (- size.z) * (i + 1))
        //     //     }

        //     //     // 新child的位置为当前child位置基础上偏移1倍的Z
        //     // }
        //     // if (child.isMesh && Array.isArray(child.material)) {
        //     //     child.material.forEach((mat) => {
        //     //         if (mat.map && mat.name === "3_boli.001") {

        //     //             const texture = mat.map
        //     //             texture.wrapS = THREE.RepeatWrapping;
        //     //             texture.wrapT = THREE.RepeatWrapping;
        //     //             texture.repeat.setX(Ztest);
        //     //             console.log('命中', mat.map)
        //     //         }
        //     //     });
        //     // }
        // });

        scaleZStrategy({
            model,
            zScale: Ztest,
        })
        scene.add(model);
    });
}

let KeyboardAborController = new AbortController()

const handleAddDevice = (type) => {
    switch (type) {
        case 'side':
            enableEditSideDevice(building);
            break;
        case 'inside':
            enableEditInSideDevice(building);
            break;
        default:
            break;
    }
}

function enableEditSideDevice(targetMesh) {
    KeyboardAborController.abort()
    KeyboardAborController = new AbortController()
    const box = new THREE.Box3().setFromObject(targetMesh);
    const center = box.getCenter(new THREE.Vector3());
    const size = box.getSize(new THREE.Vector3());
    // console.log('基准点', targetMesh.position.clone())
    camera.position.set(center.x * 3 / 2, center.y, center.z)
    orbitControls.target = new THREE.Vector3(0, center.y, center.z);

    // 监听左右方向键
    const step = 5
    document.addEventListener('keydown', (event) => {
        if (event.key === 'ArrowLeft') {
            // 向Z轴正方形移动1，且orbitControl跟随变化
            camera.position.z += step;
            orbitControls.target.z += step;
            if (transformControls.object) {
                console.log('target', transformControls.target)
                transformControls.object.position.z += step;
            }

        } else if (event.key === 'ArrowRight') {
            camera.position.z -= step;
            orbitControls.target.z -= step;
            if (transformControls.object) {
                transformControls.object.position.z -= step;
            }
        } else if (event.key === 'ArrowUp') {
            transformControls.object.position.y += 1;
        } else if (event.key === 'ArrowDown') {
            transformControls.object.position.y -= 1;
        }
    }, {
        signal: KeyboardAborController.signal
    });
    // orbitControls.enablePan = false;
    // orbitControls.enableRotate = false; //禁止旋转
    // orbitControls.enableZoom = false;//禁止缩放
    /**
     * 解决在墙上安装吸附设备
     * 目前墙体不是单独的
     * 设备安装时，只允许调整两个平面的，与墙平行的平面固定(当前为x轴)
     */
    loadByUrl('3D/device/condition.fbx', 0.2).then((model) => {
        // 获取当前orbitcontrols的target的位置

        model.rotateY(Math.PI / 2)
        const target = orbitControls.target.clone();
        // 获取模型的尺寸
        const box = new THREE.Box3().setFromObject(model);
        const size = box.getSize(new THREE.Vector3());
        // 计算模型的新位置
        model.position.set(target.x + size.x / 2, target.y, target.z);
        scene.add(model)
        // 开启编辑
        transformControls.showX = false
        transformControls.attach(model);

    })
    // TODO：结束时应该恢复orbitControls的target到0，0，0
}
/**
 * @param {THREE.Object3D} targetMesh 
 */
function enableEditInSideDevice(targetMesh) {
    KeyboardAborController.abort()
    KeyboardAborController = new AbortController()
    console.log(targetMesh)
    const box = new THREE.Box3().setFromObject(targetMesh);
    const center = box.getCenter(new THREE.Vector3());
    const size = box.getSize(new THREE.Vector3());

    camera.position.set(center.x, size.y + 50, center.z)


    /** 
     * 这里设置target后，滚动失效了
     * 测试发现必须要有一个维度是0，zoom才生效
     * y设置为0是俯视图
    */
    orbitControls.target = new THREE.Vector3(center.x, 0, center.z);

    /**
     * 设置非底面的material的透明度是0.1
     */
    targetMesh.traverse((child) => {
        if (child.isMesh) {
            // 遍历子对象，找到所有材质
            child.material.forEach(mat => {
                if (mat.name != 'red_mud_stones') {
                    mat.transparent = true;
                    mat.opacity = 0.15;
                    mat.needsUpdate = true;
                }
            });

        }
    })

    // TODO: 优化orbitControl的更新逻辑写到transfromconrol的监听事件中
    document.addEventListener('keydown', (event) => {
        const leftRightAxis = 'x'
        const leftRightStep = 2
        const upDownAxis = 'z'
        const upDownStep = 2
        if (event.key === 'ArrowLeft') {
            // 向Z轴正方形移动1，且orbitControl跟随变化
            camera.position[leftRightAxis] -= leftRightStep;
            orbitControls.target[leftRightAxis] -= leftRightStep;
            if (transformControls.object) {
                transformControls.object.position[leftRightAxis] -= leftRightStep;
            }

        } else if (event.key === 'ArrowRight') {
            camera.position[leftRightAxis] += leftRightStep;
            orbitControls.target[leftRightAxis] += leftRightStep;
            if (transformControls.object) {
                transformControls.object.position[leftRightAxis] += leftRightStep;
            }
        } else if (event.key === 'ArrowUp') {
            camera.position[upDownAxis] -= upDownStep;
            orbitControls.target[upDownAxis] -= upDownStep;
            transformControls.object.position[upDownAxis] -= upDownStep;
        } else if (event.key === 'ArrowDown') {
            camera.position[upDownAxis] += upDownStep;
            orbitControls.target[upDownAxis] += upDownStep;
            transformControls.object.position[upDownAxis] += upDownStep;
        }
    }, {
        signal: KeyboardAborController.signal
    });
    /**
     * 加载一个示例模型
     */
    loadByUrl('3D/device/waterValve.fbx', 0.5).then((model) => {
        model.rotateX(Math.PI / 2)
        const target = orbitControls.target.clone();
        // 获取模型的尺寸
        const box = new THREE.Box3().setFromObject(model);
        const size = box.getSize(new THREE.Vector3());
        // 计算模型的新位置
        model.position.set(target.x, target.y + size.y / 2, target.z);
        scene.add(model)
        /**
         * TODO: 
         * 俯视图模式，调整X + Y
         * 自由缩放模式：调整Z（仍然可以使用方向键，但是不可使用transfrom）
         * 
         */
        // transformControls.showY = false
        transformControls.attach(model)
    })

}


function changeTransformMode(mode) {
    // TODO:旋转的步长需要控制，可以监听一个按键，每次快速旋转45°
    switch (mode) {
        case 'translate': {
            transformControls.showX = true
            transformControls.showZ = true
        } break;
        case 'rotate': {
            // 插入inside设备 + 俯视图时，只允许在Y轴上旋转
            transformControls.showX = false
            transformControls.showZ = false
        }
    }
    transformControls.mode = mode;
}

/**
 * @type {Light}
 */
let light;

// 重构init函数，接收初始模式参数
function init() {
    const box = document.getElementById('THREE-canvas');
    scene = new THREE.Scene();
    camera = new THREE.PerspectiveCamera(75, box.clientWidth / box.clientHeight, 0.1, 5000);
    camera.position.set(1500, 1500, 1000);
    // camera.position.set(100, 100, 100);
    renderer = new THREE.WebGLRenderer({ antialias: true, canvas: box });
    renderer.setSize(box.clientWidth, box.clientHeight);
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setClearColor(0x000000);

    enableAxesHelper(scene)

    light = new Light({ scene })
    // 添加网格辅助线
    const grid = new THREE.GridHelper(2000, 50, 0xffffff, 0xffffff);
    grid.material.opacity = 0.2;
    grid.material.transparent = true;
    scene.add(grid);


    // 创建控制器
    orbitControls = new OrbitControls(camera, renderer.domElement);
    transformControls = new TransformControls(camera, renderer.domElement);
    transformControls.addEventListener('mouseDown', (event) => {
        console.log('鼠标按下', event);
        orbitControls.enabled = false;
    });
    transformControls.addEventListener('objectChange', () => {
        console.log('物体变化');
        renderer.render(scene, camera);
    });
    transformControls.addEventListener('mouseUp', () => {
        console.log('鼠标抬起');
        orbitControls.enabled = true;
        renderer.render(scene, camera);
    });
    scene.add(transformControls);

    // 创建CSS管理器
    cssManager = new CSSManager({ camera, scene, renderer, containerId: 'editor-box' })

    // 创建场景中的物体
    // createThings();

    loadBuilding();

    animate();

}

onMounted(() => {
    init('day');
});

onUnmounted(() => {
    if (renderer) renderer.dispose();
    TWEEN.removeAll();
});
</script>


<style lang="scss" scoped>
#container {
    width: 100%;
    height: 100%;
    display: flex;
    $panelWidth: 20%;

    #editor-box {
        width: calc(100% - #{$panelWidth});
        height: 100%;
        position: relative;

        #THREE-canvas {
            width: 100%;
            height: 100%;
            position: absolute;
            top: 0;
            left: 0;
            z-index: 1;
        }
    }

    .panel {
        display: flex;
        flex-direction: column;
        width: $panelWidth;
        height: 100%;
        background-color: #fff;

        input,
        button {
            width: 60%;
            margin-bottom: 5px;
        }
    }
}
</style>